/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package asteroide;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Random;

/**
 *
 * @author Jose Carlos Palma
 */
public class AsteroidsGame extends javax.swing.JFrame implements Runnable, KeyListener {

    //the main thread becomes the game loop
    private Thread gameLoop;
    //use this as a double buffer
    private BufferedImage backBuffer;
    //the main drawing bounding boxes
    private Graphics2D g2d;
    //toggle for drawing bounding boxes
    private boolean showBound = false;
    //create the asteroids array
    private final int ASTEROIDS = 20;
    private Asteroid[] ast = new Asteroid[ASTEROIDS];
    //create the bullet array
    private final int BULLETS = 10;
    private Bullet[] bullet = new Bullet[BULLETS];
    int currentBullet = 0;
    //the player's ship
    private Ship ship = new Ship();
    //create the identity transform (0.0)
    private AffineTransform identity = new AffineTransform();
    //Create a random number generator
    private Random rand = new Random();

    /**
     * Creates new form AsteroidsGame
     */
    public AsteroidsGame() {
        initComponents();

        setLocationRelativeTo(null);

        //Create the back buffer for smoth graphics
        backBuffer = new BufferedImage(640, 480, BufferedImage.TYPE_INT_RGB);

        g2d = backBuffer.createGraphics();

        //set up the ship
        ship.setX(320);
        ship.setY(240);

        //set up the bullets
        for (int i = 0; i < BULLETS; i++) {
            bullet[i] = new Bullet();
        }

        //create the asteroids
        for (int i = 0; i < ASTEROIDS; i++) {
            ast[i] = new Asteroid();
            ast[i].setRotationVelocity(rand.nextInt(3) + 1);
            ast[i].setX((double) rand.nextInt(600) + 20);
            ast[i].setY((double) rand.nextInt(440) + 20);
            ast[i].setMoveAngle(rand.nextInt(360));

            double ang = ast[i].getMoveAngle() - 90.0;

            ast[i].setVelX(calcAngleMoveX(ang));
            ast[i].setVelY(calcAngleMoveY(ang));

        }

        //start the user input listener
        addKeyListener(this);

        repaint();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setPreferredSize(new java.awt.Dimension(640, 480));
        setSize(new java.awt.Dimension(640, 480));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 511, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 355, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*
         * Set the Nimbus look and feel
         */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(AsteroidsGame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(AsteroidsGame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(AsteroidsGame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(AsteroidsGame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /*
         * Create and display the form
         */
        new AsteroidsGame().setVisible(true);

    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables

    public void start() {
        gameLoop = new Thread(this);
        gameLoop.start();
    }

    @Override
    public void run() {
        //acquire the current thread 
        Thread t = Thread.currentThread();
        //keep going as long as the thread is alive 
        while (t == gameLoop) {
            try {
                //update the game loop 
                //gameUpdate();
                updateShip();
                updateAsteroids();
                //target framerate is 50 fps
                Thread.sleep(50);
            } catch (InterruptedException e) {
            }
            repaint();
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {


        int keyCode = e.getKeyCode();
        switch (keyCode) {
            case KeyEvent.VK_LEFT:
                //left arrow rotates ship left 5 degrees 
                //System.out.println("LEFT");
                ship.incFaceAngle(-5);
                if (ship.getFaceAngle() < 0) {
                    ship.setFaceAngle(360 - 5);
                }
                break;
            case KeyEvent.VK_RIGHT:
                //right arrow rotates ship right 5 degrees 
                //System.out.println("RIGHT");
                ship.incFaceAngle(5);
                if (ship.getFaceAngle() > 360) {
                    ship.setFaceAngle(5);
                }
                break;
            case KeyEvent.VK_UP:
                //up arrow adds thrust to ship (1/10 normal speed) 
                //System.out.println("UP");
                ship.setMoveAngle(ship.getFaceAngle() - 90);
                ship.incVelX(calcAngleMoveX(ship.getMoveAngle()) * 0.1);
                ship.incVelY(calcAngleMoveY(ship.getMoveAngle()) * 0.1);
                break;
        }

    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    private double calcAngleMoveX(double angle) {
        return (double) (Math.cos(angle * Math.PI / 180));
    }

    private double calcAngleMoveY(double angle) {
        return (double) (Math.sin(angle * Math.PI / 180));
    }

    

    public void drawShip() {
        g2d.setTransform(identity);
        g2d.translate(ship.getX(), ship.getY());
        g2d.rotate(Math.toRadians(ship.getFaceAngle()));
        g2d.setColor(Color.ORANGE);
        g2d.fill(ship.getShape());
    }

    // drawAsteroids called by applet update event 
    public void drawAsteroids() {
//iterate through the asteroids array 
        for (int n = 0; n < ASTEROIDS; n++) {
//is this asteroid being used? 
            if (ast[n].isAlive()) {
                g2d.setTransform(identity);
                g2d.translate(ast[n].getX(), ast[n].getY());
                g2d.rotate(Math.toRadians(ast[n].getMoveAngle()));
                g2d.setColor(Color.DARK_GRAY);
                g2d.fill(ast[n].getShape());
            }
        }
    }

//draw the asteroid
    @Override
    public void paint(Graphics g) {

        //start off transforms at identity
        g2d.setTransform(identity);

        //erase the background
        g2d.setPaint(Color.BLACK);
        g2d.fillRect(0, 0, getSize().width, getSize().height);

        //print some status information 
        g2d.setColor(Color.WHITE);
        g2d.drawString("Ship: " + Math.round(ship.getX()) + ","
                + Math.round(ship.getY()), 5, 10);
        g2d.drawString("Move angle: " + Math.round(
                ship.getMoveAngle()) + 90, 5, 25);
        g2d.drawString("Face angle: " + Math.round(
                ship.getFaceAngle()), 5, 40);

        drawShip();
        drawAsteroids();

        g.drawImage(backBuffer, 0, 10, this);
    }

    // Update the ship position based on velocity 
    public void updateShip() {
        //update ship’s X position 
        ship.incX(ship.getVelX());
        //wrap around left/right 
        if (ship.getX() < -10) {
            ship.setX(getSize().width + 20);
        } else if (ship.getX() > getSize().width + 20) {
            ship.setX(-20);
        }

        //update ship’s Y position 
        ship.incY(ship.getVelY());
        //wrap around top/bottom 
        if (ship.getY() < -10) {
            ship.setY(getSize().height + 20);
        } else if (ship.getY() > getSize().height + 20) {
            ship.setY(-20);
        }
    }

    // Update the asteroids based on velocity 
    public void updateAsteroids() {
        //move and rotate the asteroids
        for (int n = 0; n < ASTEROIDS; n++) {
            
            //is this asteroid being used? 
            if (ast[n].isAlive()) {
                
                
                //update the asteroid’s X value 
                ast[n].incX(ast[n].getVelX());
                
                //warp the asteroid at screen edges 
                if (ast[n].getX() < -20) {
                    ast[n].setX(getSize().width + 20);
                } else if (ast[n].getX() > getSize().width + 20) {
                    ast[n].setX(-20);
                }
                
                //update the asteroid’s Y value 
                ast[n].incY(ast[n].getVelY());
                //warp the asteroid at screen edges 
                if (ast[n].getY() < -20) {
                    ast[n].setY(getSize().height + 20);
                } else if (ast[n].getY() > getSize().height + 20) {
                    ast[n].setY(-20);
                }
            }

            

            //update the asteroid’s rotation 
            ast[n].incMoveAngle(ast[n].getRotationVelocity());
            
            //keep the angle within 0-359 degrees 
            if (ast[n].getMoveAngle() < 0) {
                ast[n].setMoveAngle(360 - ast[n].getRotationVelocity());
            } else if (ast[n].getMoveAngle() > 360) {
                ast[n].setMoveAngle(ast[n].getRotationVelocity());
            }
        }
    }
}
